package com.whl.mybatis.builder;

import com.whl.mybatis.mapper.EntityTableMapper;
import com.whl.mybatis.mapper.PropertyColumnMapper;
import com.whl.mybatis.utils.UnderlineCamelUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.StringUtils;

import javax.persistence.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class MapperBuilder {
	public static Map<Class<?>, EntityTableMapper> tableNameMap = new ConcurrentHashMap<>();

	public static EntityTableMapper getEntityTableMapper(Class<?> mapperInterface) {
		EntityTableMapper entityTableMapperCache = tableNameMap.get(mapperInterface);
		if (entityTableMapperCache != null) {
			return entityTableMapperCache;
		}
		EntityTableMapper entityTableMapper = new EntityTableMapper();
		entityTableMapper.setMapperInterface(mapperInterface);
		entityTableMapper.setNamespace(mapperInterface.getName());
		List<PropertyColumnMapper> fieldColumnMappers = new ArrayList<>();
		Class<?> entityClass = getEntityClass(mapperInterface);
		entityTableMapper.setEntityClass(entityClass);
		// 获取表名
		Table table = entityClass.getAnnotation(Table.class);
		if (table != null && StringUtils.isEmpty(table.name()) != true) {
			entityTableMapper.setTableName(table.name());
		} else {
			entityTableMapper.setTableName(entityClass.getSimpleName());
		}

		// 获取字段与数据库列
		ReflectionUtils.doWithFields(entityClass, new FieldCallback() {
			@Override
			public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
				Transient transient_ = field.getAnnotation(Transient.class);
				if (transient_ != null) {
					return;
				}
				PropertyColumnMapper propertyColumnMapper = new PropertyColumnMapper();
				String fieldName = field.getName();
				propertyColumnMapper.setFieldName(fieldName);
				String columnName = "";
				Column column = field.getAnnotation(Column.class);
				if (column != null && !StringUtils.isEmpty(column.name())) {
					columnName = column.name();
				} else {
					columnName = UnderlineCamelUtils.camel2underline(fieldName, false);
				}
				propertyColumnMapper.setColumnName(columnName);
				Id id = field.getAnnotation(Id.class);
				if (id != null) {
					propertyColumnMapper.setIsPrimaryKey(true);
					entityTableMapper.setKeyProperty(fieldName);
					entityTableMapper.setKeyColumn(columnName);
					GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
					if (GenerationType.AUTO.equals(generatedValue.strategy())) {
						entityTableMapper.setUseGeneratedKeys(true);
					} else {
						entityTableMapper.setUseGeneratedKeys(false);
					}
				} else {
					propertyColumnMapper.setIsPrimaryKey(false);
				}
				fieldColumnMappers.add(propertyColumnMapper);
			}
		});
		entityTableMapper.setPropertyColumnMappers(fieldColumnMappers);
		return entityTableMapper;
	}

	private static Class<?> getEntityClass(Class<?> mapperInterface) {
		Type[] interfacesTypes = mapperInterface.getGenericInterfaces();
		for (Type t : interfacesTypes) {
			Type[] genericType2 = ((ParameterizedType) t).getActualTypeArguments();
			for (Type t2 : genericType2) {
				try {
					return Class.forName(t2.getTypeName());
				} catch (ClassNotFoundException e) {
					throw new RuntimeException(t2.getTypeName() + "not found");
				}
			}
		}
		return null;
	}

}
